#![allow(unused)]
use {
    bip39::{Language, Mnemonic, MnemonicType, Seed},
    hex::ToHex,
    hmac::{Hmac, Mac},
    libsecp256k1::{PublicKey, SecretKey},
    repository::model::dapp_wallet::DAppWallet,
    sha2::{Sha256, Sha512},
    sha3::{Digest, Keccak256},
};

pub fn generate_wallet() -> DAppWallet {
    let mnemonic = Mnemonic::new(MnemonicType::Words24, Language::English);
    let phrase = mnemonic.phrase();

    let mnemonic = Mnemonic::from_phrase(phrase, Language::English).unwrap();
    let seed = Seed::new(&mnemonic, "");
    let seed_bytes = seed.as_bytes();

    let (eth_pr, eth_pk) = eth_wallet_from_seed(&seed_bytes);
    let (tron_pr, tron_pk) = tron_wallet_from_seed(&seed_bytes);

    DAppWallet {
        id: None,
        mnemonic: phrase.to_string(),
        eth_pr,
        eth_pk,
        tron_pr,
        tron_pk,
    }
}

pub fn generate_wallet_by_mnemonic(phrase: &str) -> DAppWallet {
    let mnemonic = Mnemonic::from_phrase(phrase, Language::English).unwrap();
    let seed = Seed::new(&mnemonic, "Yym@home2013");
    let seed_bytes = seed.as_bytes();

    let (eth_pr, eth_pk) = eth_wallet_from_seed(&seed_bytes);
    let (tron_pr, tron_pk) = tron_wallet_from_seed(&seed_bytes);

    DAppWallet {
        id: None,
        mnemonic: phrase.to_string(),
        eth_pr,
        eth_pk,
        tron_pr,
        tron_pk,
    }
}

fn eth_wallet_from_seed(seed: &[u8]) -> (String, String) {
    let mut mac = Hmac::<Sha512>::new_from_slice("ed25519 seed".as_ref()).unwrap();
    mac.update(&seed);
    let bytes = mac.finalize().into_bytes();

    let master_secret_bytes: [u8; 32] = bytes[0..32].try_into().unwrap();
    let pr = hex::encode(master_secret_bytes);

    let sk = SecretKey::parse_slice(&master_secret_bytes).unwrap();
    let public = PublicKey::from_secret_key(&sk);
    let mut public_bytes = [0u8; 64];
    public_bytes[..].copy_from_slice(&public.serialize()[1..]);

    let mut hasher = Keccak256::new();
    hasher.update(public_bytes);
    let ret = hasher.finalize();

    let address_bytes = &ret[12..];
    let pk = hex::encode(address_bytes);

    (pr, pk)
}

fn tron_wallet_from_seed(seed: &[u8]) -> (String, String) {
    let mut mac = Hmac::<Sha512>::new_from_slice("ed25519 seed".as_ref()).unwrap();
    mac.update(&seed);
    let bytes = mac.finalize().into_bytes();

    let master_secret_bytes: [u8; 32] = bytes[0..32].try_into().unwrap();
    let pr = hex::encode(master_secret_bytes);

    let sk = SecretKey::parse_slice(&master_secret_bytes).unwrap();
    let public = PublicKey::from_secret_key(&sk);
    let mut public_bytes = [0u8; 64];
    public_bytes[..].copy_from_slice(&public.serialize()[1..]);

    let mut hasher = Keccak256::new();
    hasher.update(public_bytes);
    let digest = hasher.finalize();

    let mut raw = [0x41; 21];
    raw[1..21].copy_from_slice(&digest[digest.len() - 20..]);

    let mut hasher = Sha256::new();
    hasher.update(raw.as_ref());
    let digest1 = hasher.finalize();

    let mut hasher = Sha256::new();
    hasher.update(&digest1);
    let digest2 = hasher.finalize();

    let mut raw = raw.as_ref().to_owned();
    raw.extend(&digest2[..4]);

    let pk = bs58::encode(raw).into_string();

    (pr, pk)
}

pub fn tron_public_key_from_secret_key(sk: &SecretKey) -> String {
    let public = PublicKey::from_secret_key(&sk);
    let mut public_bytes = [0u8; 64];
    public_bytes[..].copy_from_slice(&public.serialize()[1..]);

    let mut hasher = Keccak256::new();
    hasher.update(public_bytes);
    let digest = hasher.finalize();

    let mut raw = [0x41; 21];
    raw[1..21].copy_from_slice(&digest[digest.len() - 20..]);

    let mut hasher = Sha256::new();
    hasher.update(raw.as_ref());
    let digest1 = hasher.finalize();

    let mut hasher = Sha256::new();
    hasher.update(&digest1);
    let digest2 = hasher.finalize();

    let mut raw = raw.as_ref().to_owned();
    raw.extend(&digest2[..4]);

    let pk = bs58::encode(raw).into_string();

    pk
}


pub fn tron_public_key_from_pr(pr: &str) -> String {
    let master_secret_bytes = hex::decode(pr).unwrap();
    let sk = SecretKey::parse_slice(&master_secret_bytes).unwrap();
    let pk = tron_public_key_from_secret_key(&sk);

    pk
}